/**
 * 
 */
package edu.cmu.km.kernel.tree.xml;

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.*;

import edu.cmu.km.core.Node;
import edu.cmu.km.core.Tree;

/**
 * @author Lucas Xu
 * 
 */
public class XMLReader {

	public static Tree<XMLNodeData> loadXMLDoc(File xmlFile) {
		Document doc = null;
		try {

			// Get Document Builder Factory
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();

			// Turn on validation, and turn off namespaces
			factory.setValidating(false);
			factory.setNamespaceAware(false);

			// Obtain a document builder object
			DocumentBuilder builder = factory.newDocumentBuilder();

			// Parse the document
			doc = builder.parse(xmlFile);

		} catch (ParserConfigurationException e) {
			System.out.println("The underlying parser does not support "
					+ "the requested features.");
			e.printStackTrace();
		} catch (FactoryConfigurationError e) {
			System.out.println("Error occurred obtaining Document Builder "
					+ "Factory.");
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

		Tree<XMLNodeData> tree = doc2tree(doc);
		return tree;
	}

	/**
	 * Convert a DOM document to a Tree structure. Internal, each node in the
	 * tree T data, where T will be type org.w3c.dom.Node and data be
	 * <org.w3c.dom.Node> xmlNode
	 * 
	 * @param doc
	 * @return
	 */
	private static Tree<XMLNodeData> doc2tree(Document doc) {
		Tree<XMLNodeData> tree = new Tree<XMLNodeData>();
		Node<XMLNodeData> root = buildNode(doc);
		tree.setRootElement(root);
		return tree;
	}

	/**
	 * utility method to construct a tree Node from a node in DOM. This method
	 * will be called in doc2tree
	 * 
	 * @param xmlNode
	 * @return
	 */
	private static Node<XMLNodeData> buildNode(org.w3c.dom.Node xmlNode) {
		XMLNodeData data = new XMLNodeData(xmlNode);
		Node<XMLNodeData> node = new Node<XMLNodeData>(data);
		NodeList children = xmlNode.getChildNodes();
		if (xmlNode.hasChildNodes()) {
			for (int i = 0; i < children.getLength(); i++) {
				// it's an empty text node
				if (children.item(i).getNodeType() == org.w3c.dom.Node.TEXT_NODE
						&& children.item(i).getNodeValue().trim().length()==0)
					continue;
				else
					node.addChild(buildNode(children.item(i)));
			}
		}
		return node;
	}

	public static Tree<XMLNodeData> loadXMLDoc(String xmlFilePath) {
		File xmlFile = new File(xmlFilePath);
		return loadXMLDoc(xmlFile);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String xmlfile = args[0];
		Tree<XMLNodeData> tree = loadXMLDoc(xmlfile);
		tree.printTree();
	}

}
